Questions
5 of 14
1What does HNSW stand for, and at a high level, how does it achieve sub-linear approximate nearest-neighbor search?
2What do the HNSW parameters m and ef_construct control, and what trade-off do they represent?
3What does the query-time parameter ef (search breadth) control, and how would you use it to trade off recall against latency?
4Why might increasing m significantly improve recall on one dataset but barely help - or even hurt latency - on another?
5Why does Qdrant set m: 0 on a named vector used purely for reranking (e.g. a ColBERT multivector)?
6What problem does vector quantization solve, and what is the fundamental trade-off it introduces?
7Compare scalar quantization, product quantization, and binary quantization in Qdrant in terms of compression ratio and accuracy impact.
8What are oversampling and rescoring in the context of binary quantization, and why are they necessary?
9What newer quantization options - beyond the original scalar, product, and binary trio - has Qdrant introduced to fine-tune the compression/accuracy curve?
10What is Inline Storage, and how does embedding quantized vectors directly into HNSW graph nodes improve disk-based search performance?
11What is a multivector point, and how does it differ from a point with several named vectors?
12How does late-interaction scoring (as used by ColBERT-style models) with MaxSim differ from comparing two single dense vectors?
13Why is late-interaction reranking typically applied to a small candidate set rather than the entire collection?
14Design a three-stage retrieval pipeline using dense retrieval, sparse retrieval, fusion, and ColBERT reranking. What does each stage contribute?
05 / 14

Why does Qdrant set m: 0 on a named vector used purely for reranking (e.g. a ColBERT multivector)?

m: 0 disables graph construction for vectors that are never searched directly

Setting m to 0 on a named vector tells Qdrant to skip HNSW graph construction entirely for that vector. It still stores the vectors, you can still retrieve them, and you can still score against them - you just cannot run an approximate nearest-neighbor search that originates from that vector. This is exactly what you want for a vector that is only ever used as a reranking field. In a ColBERT-style late-interaction setup, the multivector field is not used to find candidates; it is used to rescore a small set of candidates that were found by a cheaper first-stage retriever (dense or sparse). Building an HNSW graph for it would be wasted memory, wasted build time, and wasted index maintenance, because no query ever traverses that graph.

The mechanism matters because HNSW graph construction is the expensive part of indexing, not vector storage. For a multivector field with, say, 128 token vectors per point, building an HNSW graph over all those token vectors would be hundreds of times more expensive than for a single-vector field, and the resulting graph would be enormous. Since the field is only ever scored against a candidate set of, say, 100 points, the approximate search that HNSW provides is useless - you are doing exact MaxSim over 100 candidates, which is a few milliseconds at most. So m: 0 is not a limitation, it is the correct configuration. The same logic applies to any named vector that is only used for reranking or for exact scoring: set m: 0 to save the index cost and rely on the first-stage retriever to provide candidates. The only thing you lose is the ability to do a direct ANN search against that field, which is exactly the operation you have decided you do not need.

  1. 1

    m: 0 on a named vector disables HNSW for that field only; other fields keep their own index configuration.

  2. 2

    The vectors are still stored and still retrievable; you can still score against them with an exact distance.

  3. 3

    The field cannot be the top-level query target in a query_points call unless you also provide a prefetch, because there is no index to search.

  4. 4

    Memory savings can be substantial for multivector fields, where the graph would otherwise dominate the index footprint.

The trade-off is that you must always have a first-stage retriever feeding the reranker. If you ever need to search directly against the multivector field - for example, to evaluate recall of the reranker in isolation - you have to either use exact search over a small candidate set or temporarily build an index. This is a real constraint, and it is why some teams keep a separate small collection with an indexed multivector for evaluation. The common mistake is thinking m: 0 means the vector is disabled or ignored. It does not - it is stored, it participates in scoring, it just does not get a graph. Another common mistake is setting m: 0 on a vector that is actually used as a first-stage retriever, which results in queries that silently fall back to a full scan or fail, depending on the query shape. If you see unexpectedly slow queries on a collection with m: 0 on the query field, that is almost always the cause. Version note: the ability to set per-vector hnsw_config (including m: 0) has been available for several releases, but the exact interaction with multivector fields and with the prefetch/fusion API has evolved - check the release notes for your version.

javascript

Version-dependent: the per-vector hnsw_config override (including m: 0) and the multivector_config with MAX_SIM comparator are part of the qdrant-client 1.10+ API surface. On older versions, multivector support and per-vector index overrides were more limited or absent, so verify against your version before copying this configuration.

Difficulty: 8/10
Topics: HNSW, Multivector, Late Interaction

Scenario Questions

0-2 years experience
  1. 1

    You set m: 0 on a named vector and now queries against that field are extremely slow. Explain what is happening and how to fix the query shape.

  2. 2

    A teammate thinks m: 0 means the vectors are not stored. How would you demonstrate that they are still stored and still used in scoring?

2-5 years experience
  1. 1

    You have a collection with a dense field and a ColBERT field, both indexed with m: 16. Memory is 3x over budget. What do you change first and what recall impact do you expect?

  2. 2

    A new engineer adds a reranking field and forgets to set m: 0. Build time quadruples. Walk through how you would diagnose this and what the fix looks like.

5-8 years experience
  1. 1

    Design a collection schema for a hybrid search system with dense, sparse, and ColBERT fields. Which fields get an index, which get m: 0, and how do you keep the total index memory under a fixed budget?

  2. 2

    You need to support both a fast endpoint (dense only, top-10) and a high-quality endpoint (dense + ColBERT rerank, top-10) on the same collection. How do you configure the collection so both endpoints share storage but have different latency profiles?

8+ years experience
  1. 1

    A product decision requires direct ANN search on the ColBERT field for a new feature, but the memory budget cannot support a full HNSW graph over all token vectors. Propose a design that supports the feature without building a full graph, and quantify the recall/latency trade-off.

  2. 2

    You must migrate a 500M-point collection from a single-vector schema to a dense + ColBERT schema with m: 0 on the reranker, with zero downtime. Describe the migration, including how you backfill the multivector field and how you validate reranker quality before cutover.

Follow-up Questions

  • How would you evaluate the reranker's recall in isolation if the multivector field has no index, and what would you build to make that evaluation practical?
  • If you later decide the multivector field should also support direct search for a new product feature, what is the migration path and what is the memory and build-time impact?